#include <vcl.h>
#include <float.h>  //Pour _isnan
#pragma hdrstop

#include <EIC.h>
#include "MTAG_CtrlStd.h"
#include "uNombre.h"
#include "CEditNum.h"

#pragma link "CEdit"
#pragma package(smart_init)

#define MODULE_TAG MTAG_CEDITNUM

//---------------------------------------------------------------------------
// ValidCtrCheck est utilisé pour être sûr que les composants créés ne
// contiennent aucune fonction virtuelle pure.
//

static inline void ValidCtrCheck(CEditNum *)
    {
    new CEditNum(NULL);
    }



//////////////////////////////////////
//
// CEditNum
//
// Fonction: Constructeur
//
// P.E.:
//
// P.S.: AUCUN
//
//////////////////////////////////////
__fastcall CEditNum::CEditNum(TComponent* Owner)
   : CCustomEdit(Owner)
{
try
   {
   FColorNeg              = clRed;
   FColorPositive         = clWindowText;
   FMask                  = "###########.##";
   FMax                   = 99999999999.99;
   FMin                   = D_NS;
   inherited::Text        = "0"+AnsiString(DecimalSeparator)+"00";
   FTypeVal               = eDouble;
   FNSActive              = false;
   m_ValNS                = D_NS;
   inherited::Alignment   = taRightJustify;
   bFlagExec              = true;
   FbCalc                 = false;
   m_OnCorrectValue       = NULL;
   m_OnChange             = NULL;
   inherited::OnChange    = MyOnChange;

   m_pOnExit             = NULL;
   inherited::OnExit     = MyOnExit;

   m_pOnEnter            = NULL;
   inherited::OnEnter    = MyOnEnter;

   m_pbCalc  = NULL;
   Calc = NULL;
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(0), e);
   }
}

void __fastcall CEditNum::ReadMax(TReader* Reader)
{
try
   {
   FMax = AnsiToDouble(Reader->ReadString());
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(2), e);
   }
}

void __fastcall CEditNum::WriteMax(TWriter* Writer)
{
try
   {
   Writer->WriteString(DoubleToAnsi(FMax));
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(3), e);
   }
}

void __fastcall CEditNum::ReadMin(TReader* Reader)
{
try
   {
   FMin = AnsiToDouble(Reader->ReadString());
   }
catch(EOverflow &e)
   {
   FMin = D_NS;
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(4), e);
   }
}

void __fastcall CEditNum::WriteMin(TWriter* Writer)
{
try
   {
   Writer->WriteString(DoubleToAnsi(FMin));
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(5), e);
   }
}

void __fastcall CEditNum::ReadValeurNS(TReader* Reader)
{
try
   {
   m_ValNS = AnsiToDouble(Reader->ReadString());
   }
catch(EOverflow &e)
   {
   m_ValNS = D_NS;
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(6), e);
   }
}

void __fastcall CEditNum::WriteValeurNS(TWriter* Writer)
{
try
   {
   Writer->WriteString(DoubleToAnsi(ValeurNS));
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(7), e);
   }
}

void __fastcall CEditNum::DefineProperties(TFiler* Filer)
{
try
   {
   /// Lorsque le champ EICDatas existe, il contient les valeurs des propriétés
   /// Min, Max, Valeur et ValNS.
   /// Cette propriété binaire n'étant pas pratique, ces propriétés sont désormais
   /// stockés dans les champs associés. Le champ EICDatas n'est donc plus stocké,
   /// et devrait disparaître.
   ////////////////////////////////////////////////////////////////////////////
   Filer->DefineBinaryProperty("EICDatas", ReadDatas, NULL, true);

   /// Les propriétés Min, Max, Valeur et ValNS sont des doubles. Lorsque ces valeurs valent
   /// D_NS, leur restauration est incorrecte.
   /// De plus, Builder ne stocke pas la valeur de ses propriétés lorsqu'elles sont égales à 0.
   /// Par conséquent, elles ne sont pas enregistrés dans la DFM via l'interface de Builder,
   /// mais via les fonctions WriteMin ...
   ////////////////////////////////////////////////////////////////////////////
   Filer->DefineProperty("LeMax"     , ReadMax     , WriteMax     , true);
   Filer->DefineProperty("LeMin"     , ReadMin     , WriteMin     , true);
   Filer->DefineProperty("LaValeurNS", ReadValeurNS, WriteValeurNS, true);

   inherited::DefineProperties(Filer);
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(20), e);
   }
}

void __fastcall CEditNum::ReadDatas(TStream *Stream)
{
AnsiString aValue;
TNotifyEvent SveOnChange = NULL;;
double dValeur;

try
   {
   SveOnChange = OldOnChange;
   m_OnChange  = OldOnChange = NULL;

   aValue = ReadString( Stream );
   if( aValue == "D_NS" )
       Min = D_NS;
   else
       {
       Min     = atof( aValue.c_str());
       if( Min < D_NS )
           Min = D_NS;
       }
   if( _isnan(Min))
       Min = D_NS;

   aValue = ReadString( Stream );
   if( aValue == "D_NS" )
       Max     = D_NS;
   else
       {
       Max     = atof( aValue.c_str());
       if( Max < D_NS )
           Max = D_NS;
       }
   if( _isnan(Max))
       Max = D_NS;

   aValue = ReadString( Stream );
   if( aValue == "D_NS" )
       dValeur  = D_NS;
   else
       {
       dValeur  = atof( aValue.c_str());
       if( dValeur < D_NS )
           dValeur = D_NS;
       }
   if( _isnan(dValeur))
       dValeur = D_NS;

   aValue = ReadString( Stream );
   if( aValue == "D_NS" )
       m_ValNS   = D_NS;
   else
       {
       m_ValNS   = atof( aValue.c_str());
       if(m_ValNS < D_NS)
           m_ValNS = D_NS;
       }
   if( _isnan(m_ValNS))
       m_ValNS = D_NS;

   //On affecte valeur après avoir initialisé ValeurNS, car dans le cas contraire,
   //SI Valeur = -2147483647 et si Mask = ####
   //ALORS valeur est différent de Valeur NS, donc on applique le masque ce qui donne -2147 !!!!    
   Valeur = dValeur;

   m_OnChange  = OldOnChange = SveOnChange;
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(30), e);
   }
}



int __fastcall CEditNum::ReadInteger(TStream *Stream)
    {
    int nValue;
    Stream->ReadBuffer(&nValue, sizeof(nValue));
    return nValue;
    }



AnsiString __fastcall CEditNum::ReadString(TStream *Stream)
    {
    char szValue[256];
    int  nLength = ReadInteger(Stream);
    Stream->ReadBuffer(szValue, nLength);
    return AnsiString(szValue);
    }

//////////////////////////////////////
//
// SetMask
//
// Fonction: Initialise le Mask de saisie
//
// P.E.: Le Mask
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CEditNum::SetMask( const AnsiString aMask )
{
AnsiString  aTmp;
int         Pos;
int         iTmp;

try
   {
   FMask = aMask;

   //Si la valeur entière fait plus de 14 caractères
   //On la réduit à 14 caractères
   iTmp = FMask.LastDelimiter(".,")-1;
   if (iTmp == -1)
      iTmp = FMask.Length();
   if (iTmp > MAXMASK)
      FMask.Delete(1, iTmp - MAXMASK);

    aTmp = GetMaskNumeric();

    if(aTmp.Length() != 0)
       FMax = min(FMax, aTmp.ToDouble());
    else
       {
       ASSERT(false); //A quoi ça sert ???
       SetTypeVal(FTypeVal);
       }

    SetMaxLength();

    DecompNum(aTmp, NULL, NULL, &Pos);

    // Pt decimal existe
   if( Pos != 0 && FTypeVal != eFloat && FTypeVal != eDouble && FTypeVal != eCurrency )
        TypeValeur = eDouble;
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(70), e);
   }
}



//////////////////////////////////////
//
// SetMax
//
// Fonction: Initialise Max
//
// P.E.: Max
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CEditNum::SetMax(double dMax)
    {
    //Le maximum ne peut pas être supérieur au mask et à +ValNS
    FMax = min(GetMaskNumeric().ToDouble(), min(fabs(GetDefaultValNS()), dMax));
    }



//////////////////////////////////////
//
// SetMaxLength
//
// Fonction: Initialise la longueur Max du Num
//
// P.E.: 
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CEditNum::SetMaxLength()
    {
    if( Mask.IsEmpty())
       {
       ASSERT(false); //A quoi ça sert ??? Le mask peut être vide ????

       inherited::MaxLength = MAXMASK + CalcNbSpaces();
       }
    else
       {
       inherited::MaxLength = Mask.Length() + CalcNbSpaces();

       if (FMin < 0) //Si le nombre peut-être négatif, on rajoute le '-'
          inherited::MaxLength ++;
       }
    }



//////////////////////////////////////
//
// SetMin
//
// Fonction: Initialise Min
//
// P.E.: Min
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CEditNum::SetMin( double dMin )
    {
    if (FMin == dMin)
       return;

    //Le minimum ne peut pas être inférieur au mask et à -ValNS
    FMin = max(-GetMaskNumeric().ToDouble(), max(-fabs(GetDefaultValNS()), dMin));

    SetMaxLength();
    }



//////////////////////////////////////
//
// SetNSActive
//
// Fonction: Initialise NSActive
//
// P.E.: NSActive
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CEditNum::SetNSActive(bool bNSActive)
   {
   FNSActive    = bNSActive;
   }

/*******************************************************************************

Fonction :

P.E :

P.E modifiés :

P.S :
*******************************************************************************/
void __fastcall CEditNum::SetStateNS(bool bStateNS)
{
//Aucun traitement n'est effectué quand bStateNS = false car on ne connait pas le nb à afficher
if(!ComponentState.Contains(csDesigning))
   ASSERT(bStateNS);

if (bStateNS && FNSActive)
   Text = EmptyStr;
}

/*******************************************************************************

Fonction :

P.E :

P.E modifiés :

P.S :
*******************************************************************************/
void __fastcall CEditNum::SetFbCalc( bool bCalc )
{
   //Si l'état ne change pas.
   if (bCalc && m_pbCalc || !bCalc && !m_pbCalc)
      return;

    FbCalc = bCalc;

   AfficherBoutonCalculette(ComponentState.Contains(csDesigning) && bCalc
                           || bCalc && Focused() && Enabled && !ReadOnly);
}

/*******************************************************************************

Fonction :

P.E :

P.E modifiés :

P.S :
*******************************************************************************/
bool __fastcall CEditNum::GetStateNS() /*const*/
{
//Le texte est vide lorsque l'on interroge la propriété NS sur un OnChange
//ET que l'on vient de supprimer le contenu du composant.
//=> D'où l'obligation de tester également le NSActive.
return NSActive && inherited::Text.IsEmpty();
}



//////////////////////////////////////
//
// SetText
//
// Fonction: Initialise Text
//
// P.E.: Text
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CEditNum::SetText( const AnsiString aText )
{
int         iPosSep;
AnsiString _aText(aText);

 try
     {
     if((iPosSep = _aText.LastDelimiter(".,")) != 0 && _aText[iPosSep] != ThousandSeparator)
        _aText[iPosSep] = DecimalSeparator;

     if( ComponentState.Contains( csDesigning ))
         {
         if( IsNumValid( Concatene( _aText )))
            {
            if(!_aText.IsEmpty() && Concatene(_aText).ToDouble() != m_ValNS || FNSActive)
               inherited::Text = _aText;
            else
               inherited::Text = EmptyStr;
            }
         }
     else
         {
         if(!_aText.IsEmpty() || FNSActive)
             inherited::Text = _aText;
         }
     }
 catch( ... )
     {
     ASSERT(false);
     }
}



//////////////////////////////////////
//
// SetTypeVal
//
// Fonction: Initialise le type de Numeric utilise
//           ainsi que son Max et sa valeur NS
//
// P.E.: TypeVal
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CEditNum::SetTypeVal( enum TypeVal eTypeValeur )
   {
   FTypeVal = eTypeValeur;

   if(ComponentState.Contains(csLoading)) //Inutile de lancer ce code pendant le chargement car il pourrait écraser le mask paramétré
      return ;

   if (eTypeValeur == eFloat || eTypeValeur == eDouble)
      FMask = "###########.##";
   else if (eTypeValeur == eCurrency)
      FMask = "###############.####";
   else if (eTypeValeur == eInt || eTypeValeur == eLong || eTypeValeur == eUInt)
      FMask = "##########";
   else if (eTypeValeur == eShInt || eTypeValeur == eUShInt)
      FMask = "#####";

   m_ValNS = GetDefaultValNS();
   switch( eTypeValeur )
        {
        case eShInt:
            FMax    = SHRT_MAX;
            break;

        case eUShInt:
            FMax    = USHRT_MAX;
            break;

        case eInt:
            FMax    = INT_MAX;
            break;

        case eUInt:
            FMax    = UINT_MAX;
            break;

        case eLong:
            FMax    = LONG_MAX;
            break;

      case eFloat:
            FMax    = MAXMAX;
            break;

      case eDouble:
      case eCurrency:
            FMax     = MAXMAX;
            break;

        default :
            ASSERT(false);
            FMax     = MAXMAX;
        }

    if (eTypeValeur == eUShInt || eTypeValeur == eUInt)
       FMin = 0;
    else
       FMin = m_ValNS;

    if (!Text.IsEmpty())
       SetValue(Text.ToDouble()); //Pour mettre à jour le formatage (suppression des décimales si on passe en long ...)
    }



//////////////////////////////////////
//
// SetValue
//
// Fonction: Initialise la valeur du Numeric
//
// P.E.: Valeur
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CEditNum::SetValue( double dValeur )
   {
   int      iNbDecim;
   double    dVopieVal;

   DecompNum(GetMaskNumeric(), NULL, &iNbDecim, NULL);
   dVopieVal = Arrond( dValeur, iNbDecim );

   if(dValeur == m_ValNS && NSActive || IsNumValid(dVopieVal))
      {
      if( dValeur == m_ValNS && NSActive )
         inherited::Text = EmptyStr;   //Ca lance le OnChange, StateNS doit donc être affecté avant (des fois qu'il serait utilisé dans le OnChange ...)
      else if(Focused()) //SI focus, il faut supprimer les séparateurs de milliers
         {
         inherited::Text = Concatene(Format(AnsiString(dVopieVal)));

         SelStart       = 0;
         SelLength      = inherited::Text.Length();
         }
      else
         //On formate le texte (Pour forcer le respect du masque)
         inherited::Text = Format(AnsiString(dVopieVal));
      }

   Modified = false;
   }


/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres de sortie :

Valeur retournée :
*******************************************************************************/
void __fastcall CEditNum::SetValNS(double dNouvelleValNS)
   {
   if (inherited::Text.IsEmpty())
      {
      if (dNouvelleValNS != m_ValNS)
         inherited::Text = m_ValNS;
      }
   else if (FNSActive && Concatene(inherited::Text).ToDouble() == dNouvelleValNS)
      inherited::Text = EmptyStr;

   m_ValNS = dNouvelleValNS;
   }


//////////////////////////////////////
//
// GetValue
//
// Fonction: Renvoie Valeur
//
// P.E.: AUCUN
//
// P.S.: Valeur
//
//////////////////////////////////////
double __fastcall CEditNum::GetValue()
   {
   if (inherited::Text.IsEmpty())
      {
      if (FNSActive)
         return m_ValNS;
      else
         return max(Min, .0);
      }
   else if (inherited::Text == "-")
      return max(Min, .0);
   else
      return Concatene(inherited::Text).ToDouble();
   }

//////////////////////////////////////
//
// GetText
//
// Fonction: Renvoie Text
//
// P.E.: AUCUN
//
// P.S.: Text
//
//////////////////////////////////////
AnsiString __fastcall CEditNum::GetText() 
   {
   if (inherited::Text.IsEmpty() && !FNSActive)
      return max(Min, .0);
   else
      return inherited::Text;
   }



//////////////////////////////////////
//
//  GetMaxLength
//
// Fonction: Renvoie la longueur max du Num
//
// P.E.: AUCUN
//
// P.S.: MaxLength
//
//////////////////////////////////////
int __fastcall CEditNum::GetMaxLength() const
    {
    return inherited::MaxLength;
    }





//////////////////////////////////////
//
//
//
// Fonction: KeyDown( Word &Key, Classes::TShiftState Shift )
//
// P.E.: AUCUN
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CEditNum::KeyDown( Word &Key, Classes::TShiftState Shift )
   {
   AnsiString  aTmp        = Text;
   int         PosDec;
   bool      bSigned;

   m_OnChange = NULL;

   if(Shift.Contains(ssCtrl))
      {
      switch(Key)
         {
         case 'X':
         case 'x':
            CutToClipboard();
            break;

         case 'C':
         case 'c':
            CopyToClipboard();
            break;

         case 'V':
         case 'v':
            if(Clipboard()->HasFormat(CF_TEXT) && IsClipboardValid())
               SetSelTextBuf(Clipboard()->AsText.c_str());
            else
               Key = VK_CANCEL;
            break;
         }
      }

   switch(Key)
      {
      case VK_DELETE:
         {
         if(!ReadOnly)
            {
            DecompNum(aTmp, NULL, NULL, &PosDec);
            //Si l'on veut supprimer le séparateur décimal
            if(PosDec && SelStart == PosDec - 1)
               {
               aTmp.Delete(PosDec, 1);
               if(!IsNumValid(Concatene(aTmp)))
                  Key = VK_CANCEL;
               }
            else
               {
               aTmp.Delete( SelStart + 1, max(SelLength, 1));
               if(aTmp.AnsiCompare("-") == 0 && Min >= 0)
                  break;
               if(!IsNumValid(Concatene(aTmp)))
                  Key = VK_CANCEL;
               }
            }
         else
            Key = VK_CANCEL;
         break;
         }
      }

   m_OnChange = OldOnChange;

   inherited::KeyDown( Key, Shift );
   }



//////////////////////////////////////
//
//
//
// Fonction: KeyPress( char &Key )
//
// P.E.: AUCUN
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CEditNum::KeyPress( char &Key )
    {
    AnsiString aText    = Text;

    int iNbDecimMask;   //Nombre de decimales du Mask
    int iNbEntierMask;
    int iNbEntierNum;

    int SizeMax;
    int PosDec;
    bool bSigned;

   if(ReadOnly)
      {
      Key = VK_CANCEL;
      return;
      }

   try
      {
      // Test selection
      if( SelLength != 0 )
         aText = EmptyStr;    //Le texte sélectionné va être supprimé (BUGGE : Lorsque le texte n'est pas sélectionnée en totalité, il n'est pas supprimé en totalité)

      SizeMax = FMask.Length();
      if( SizeMax == 0 )
         SizeMax = MAXMASK;

      // Calcul taille entier & decimal du Mask
      /////////////////////////////////////////
      DecompNum(GetMaskNumeric(), &iNbEntierMask, &iNbDecimMask, NULL);

      // Calcul taille entier & decimal de l'EditNum
      //////////////////////////////////////////////
      bSigned = DecompNum(aText, &iNbEntierNum, NULL, &PosDec);
      if( bSigned )
         iNbEntierMask ++;
      }

   catch( Exception &e)
      {
      EICDisplayException( TAG(10), e );
      }

    try
        {
        switch( Key )
         {
         case '0':
         case '1':
         case '2':
         case '3':
         case '4':
         case '5':
         case '6':
         case '7':
         case '8':
         case '9':
            {
            if(aText.Length() >= SizeMax && Min >= 0)
               Key = VK_CANCEL;
            else
               {
               if( !Mask.IsEmpty())
                 {
                 if( PosDec )
                     {
                     if( PosDec > iNbEntierMask && SelStart < iNbEntierMask + 1 )
                        Key = VK_CANCEL;
                     else if( SelStart >= PosDec && aText.Length() - PosDec >= iNbDecimMask)
                        Key = VK_CANCEL;
                     }
                  else if( SelStart >= iNbEntierMask || iNbEntierNum >= iNbEntierMask)
                     Key = VK_CANCEL;

                  if( SelStart == 0 && bSigned )
                     Key = VK_CANCEL;
                  if( Key != VK_CANCEL && !IsNumInMiddle(aText, Key ))
                      Key = VK_CANCEL;
                  }
               else
                  {
                  ASSERT(false); //A quoi ça sert ??? Le mask peut être vide ????
                  if( bSigned && SelStart == 0 )
                     Key = VK_CANCEL;
                  }
               }
            break;
            }

         case SEP_DEC_2:
         case SEP_DEC:
                {
                Key = DecimalSeparator;

                if((iNbDecimMask != 0 || Mask.IsEmpty()) && aText.Length() < SizeMax - 1 )
               {
                    if( PosDec )
                        Key = VK_CANCEL;
               }
            else
               Key = VK_CANCEL;

            break;
            }

         case '-':
            {
            if( bSigned || SelStart != 0 || Min >= 0)
               Key = VK_CANCEL;
            break;
            }


         case VK_BACK:
            {
            if( PosDec && SelStart == PosDec )
               {
               aText.Delete( PosDec, 1 );
               if( !IsNumValid( Concatene( aText )))
                  Key = VK_CANCEL;
               }
            break;
            }

         default:
                Key = VK_CANCEL;
         }

      inherited::KeyPress(Key);
      }
   catch( Exception &e)
      {
      EICDisplayException( TAG(11), e );
      }
   }

/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres modifiés :

Valeur retournée :
*******************************************************************************/
void __fastcall CEditNum::KeyUp( Word &Key, Classes::TShiftState Shift )
{
try
   {
   Font->Color = (!inherited::Text.IsEmpty() && inherited::Text[1] == '-') ? FColorNeg : FColorPositive;

   inherited::KeyUp(Key, Shift);
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(20), e);
   }
}

//////////////////////////////////////
//
// WndProc
//
// Fonction: Capture les messages
//
// P.E.: Les messages
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CEditNum::WndProc( TMessage &Message )
   {
   bool bTexteModifie = false;
   Cardinal uMsg = Message.Msg;

   switch( uMsg)
      {
      case WM_SETFOCUS:
         {
         if(inherited::Text.AnsiCompare("-") != 0 )
            {
            m_OnChange = NULL;
            inherited::Text = Concatene(inherited::Text);
            m_OnChange = OldOnChange;
            }
         break;
         }

      case WM_NCPAINT:
         {
         if( !ComponentState.Contains( csDesigning ) && bFlagExec )
            {
            m_OnChange = NULL;
            if( !NSActive )
               Text = Format(Text);
            else if( Valeur == m_ValNS)
               Text = EmptyStr;
            m_OnChange = OldOnChange;
            bFlagExec = false;
            }
         break;
         }

      case WM_PASTE:
         {
         if(!Clipboard()->HasFormat(CF_TEXT) || !IsClipboardValid())
            Message.Msg = WM_NULL;
         break;
         }

      case WM_KILLFOCUS:
         {
         if(!ComponentState.Contains(csDestroying)) //Inutile de faire ce code pendant la phase de destruction car certaines propriétés peut déjà avoir été réinitialisé => ERREUR
            {
            bool bOldModified = Modified;

            //Si l'interfaçe peut permettre de corriger un nombre invalide
            //ET SI le nombre est invalide
            // => On avertie l'interfaçe qui peut opter pour une correction
            if(m_OnCorrectValue
               && !Text.IsEmpty() && (Text.AnsiCompare("-" ) == 0 || Concatene(Text).ToDouble() < Min))
               {
               double dValeur = Valeur;
               if (m_OnCorrectValue(this, &dValeur))
                  Valeur = dValeur;
               }

            //SI le nombre est toujours invalide
            if(!Text.IsEmpty() && (Text.AnsiCompare("-" ) == 0 || Concatene(Text).ToDouble() < Min))
               {
               Message.Msg = WM_NULL;
               ::SetFocus( Handle );
               }
            else
               {
               if(Text.IsEmpty())
                  {
                  if(!NSActive)
                     Valeur = max(Min, .0);
                  }
               else
                  {
                  m_OnChange = NULL; //Lorsque l'on perd le focus, les séparateurs de milliers sont ajoutés mais cela ne justifie pas le lancement du OnChange
                  Text = Format(Text);
                  m_OnChange = OldOnChange;
                  }

               Modified = bOldModified;
               }
            }

         break;
         }
      case WM_WINDOWPOSCHANGING :
           if (!Focused() && !ComponentState.Contains(csLoading))
              {
              //SI le composant est élargie
              if (((WINDOWPOS*)Message.LParam)->cx > Width)
                 {
                 //Si aucun séparateur de millier n'est affiché, le chaine peut être concaténé
                 // => voir si elle tient en version non concaténé
                 if (inherited::Text.AnsiPos(ThousandSeparator) == 0)
                    {
                    AnsiString aTexte = inherited::Text;
                    int iPosSeparateur = aTexte.AnsiPos(DecimalSeparator);
                    int iNbEntier = 3;

                    //On ajoute les séparateurs de Milliers
                    for (int i = iPosSeparateur-iNbEntier ; i > 0 ; i--, iNbEntier++)
                       if(iNbEntier % 3 == 0)
                          aTexte.Insert(ThousandSeparator, i);

                    //Si on a plus besoin de concaténer
                    if (!ConcatenerSiBesoin(&aTexte, ((WINDOWPOS*)Message.LParam)->cx))
                       {
                       m_OnChange  = NULL;
                       inherited::Text = aTexte;
                       m_OnChange = OldOnChange;
                       }
                    }
                 }
              //SI le composant est rétréci
/*BUG => Lancé lors de la création du composant avec une largeur de 0
              else if (((WINDOWPOS*)Message.LParam)->cx < Width)
                 {
                 //Si un séparateur de millier est affiché, elle ne tient peut-être plus dans le composant
                 if (inherited::Text.AnsiPos(ThousandSeparator) != 0)
                    {
                    AnsiString aTexte = inherited::Text;

                    //On concatène si besoin
                    if (ConcatenerSiBesoin(&aTexte, ((WINDOWPOS*)Message.LParam)->cx))
                       {
                       m_OnChange  = NULL;
                       inherited::Text = aTexte;
                       m_OnChange = OldOnChange;
                       }
                    }
                 }*/
              }
         break;
      }

    //SI le texte change et qu'il ne s'agit pas d'une prise de focus (entrainant la suppression des séparateurs de milliers)
    if (  Message.Msg == WM_SETTEXT
       && Concatene(AnsiString(inherited::Text)) != Concatene(AnsiString((LPCTSTR)Message.LParam)))
         bTexteModifie = true;

    inherited::WndProc( Message );

   switch( uMsg)
      {
      case WM_DESTROY :
           delete Calc;                 Calc     = NULL;
           delete m_pbCalc;             m_pbCalc = NULL;
           break;

      case WM_WINDOWPOSCHANGED : // Repositionnement des composants associés
           PositionnerBoutonCalculette();
           break;

      case WM_SETTEXT :
         if (bTexteModifie)
            Modified = true;
         break;
      }

    }



//////////////////////////////////////
//
// Concatene le texte specifie en retirant tous les espaces
//
// Fonction: Concatene( AnsiString aText )
//
// P.E.: Le text a concatene
//
// P.S.: Le nouveau texte concatene
//
//////////////////////////////////////
AnsiString CEditNum::Concatene( const AnsiString &aText ) const
    {
    int         i;
    int         iSize   = aText.Length();
    AnsiString  aTemp;

    for (i=1 ; i<=iSize ; i++)
       if(aText[i] != ThousandSeparator)
           aTemp += AnsiString(aText[i]);
    return aTemp;
    }



//////////////////////////////////////
//
// AnsiString Format(AnsiString aText)
//
// Fonction: Formate le Nombre de l'EditNum a la sortie de celui-ci
//              Si la nouvelle taille > conteneur alors pas de changement
//
// P.E.: Le Nombre
//
// P.S.: Le nouveau Nombre formate
//
// Ex: aText = "1000,2" : FMask = "#######.##"
//     Valeur renvoyee: "1 000,20"
//////////////////////////////////////
AnsiString CEditNum::Format( const AnsiString &aText)
{
int         iSize;
int         i;
int         iCnt        = 0;
int         iNbDecimalesMask;
int         PosDec;
AnsiString  aFinal;
AnsiString  aTemp       = aText;

try
   {
   if( aTemp.IsEmpty())
       return EmptyStr;

   aTemp   = Concatene( aTemp );

   DecompNum(GetMaskNumeric(), NULL, &iNbDecimalesMask, NULL);

   //Application du mask
   if(!Mask.IsEmpty())
      aTemp = FloatToStrF(aTemp.ToDouble(), ffFixed, 18, iNbDecimalesMask);
   else
      ASSERT(false); //A quoi ça sert ??? Le mask peut être vide ????

   iSize   = aTemp.Length() - 1;

   PosDec  = aTemp.Pos( AnsiString( DecimalSeparator ));
   if( PosDec != 0 )
       {
       //Extraction de la partie décimale (séparateur inclu)
       aFinal = aTemp.SubString(PosDec, aTemp.Length() - PosDec + 1);

       //On ajoute les 0 qui manquent dans la décimale (Si aFinal = 0.25 et Mask = 0.00000 => aFinale est mis à 0.25000)
       if(iNbDecimalesMask >= aFinal.Length())
           aFinal += AnsiString( "00000000000" ).SubString( 1, iNbDecimalesMask+1 - aFinal.Length());
       i = PosDec - 2;
       }
   else
       {
       if(iNbDecimalesMask != 0 )
           {
           aFinal += AnsiString(DecimalSeparator);
           aFinal += AnsiString("0000000").SubString(1, iNbDecimalesMask);
           }
       i = iSize;
       }

   // Ajoute les separateurs de milliers
   /////////////////////////////////////
   while( i >= 0 )
       {
       if( iCnt %3 == 0 && iCnt != 0 )
           {
           if( !( i == 0 && aTemp[1] == '-' ))
               aFinal.Insert(ThousandSeparator, 0);
           }
       aFinal.Insert( aTemp[i+1], 0 );
       iCnt ++;
       i --;
       }

   ConcatenerSiBesoin(&aFinal, ClientWidth);
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(280), e);
   }
return aFinal;
}



//////////////////////////////////////
//
// double Arrond( double d, int n )
//
// Fonction: Arrondit un double en double au rang n aprŠs la virgule
//
// P.E.: Le nombre
//       Le rang
//
// P.S.: Le nouveau nombre arrondi
//
//////////////////////////////////////
double CEditNum::Arrond( double d, int n )
    {
   int i;
    double ent, ent2;
    double dec, dec2, p;

    dec = modf( d, &ent); /** R‚cup‚ration parties entiŠres & d‚cimales de d **/

    p = 1.0;              /** Calcul du rang **/
    for(i=1;i<=n;i++)
        p = 10.0 * p;

    dec = p * dec;
    dec2 = fabs(modf( dec, &ent2));
    i = (.5 <= dec2) ? (dec < 0) ? -1 : 1 : 0;
    ent2 = ent2 + (double)i;
    ent2 = ent2 / p;

    return( ent + ent2);
    }


/**********************************************************************
//
bool __fastcall CEditNum::DecompNum( const AnsiString &aNum, int *_iNbEntiers, int *_iNbDecim, int *_iPosDec)
//
// Fonction: Decompose un nombre en Nbre d'entiers, de decimaux, indique la
//          position du point decimal et returne true s'il est signe
//
// P.E.: Le nombre
//       Le nombre d'entiers            ( rempli en sortie )
//       Le nombre de decimales         ( rempli en sortie )
//       La position du point decimal   ( rempli en sortie : commence a l'indice 1 )
//
// P.S.: true si signe
//
//////////////////////////////////////*/
bool __fastcall CEditNum::DecompNum( const AnsiString &aNum, int *_iNbEntiers, int *_iNbDecim, int *_iPosDec)
    {
    bool bSigned = false;
    int iNbEntiers, iNbDecim, iPosDec;

    if( aNum.Pos( "-" ) != 0 )
        bSigned  = true;

    iPosDec  = aNum.Pos( DecimalSeparator );

   if(iPosDec == 0)
        {
        iNbDecim        = 0;
        if( aNum.Length() == 0 )
            {
            if( !aNum.IsEmpty() && aNum.AnsiCompare( Mask ) == 0 )
                {
                iNbEntiers  = MAXMASK;
                if( bSigned )
                    iNbEntiers --;
                }
            else
                iNbEntiers = 0;
            }
        else
            {
            iNbEntiers  = aNum.Length();
            if( bSigned )
                iNbEntiers --;
            }
        }
    else
        {
        iNbDecim        = aNum.Length() - iPosDec;
        iNbEntiers      = aNum.Length() - iNbDecim - 1;
        if( bSigned )
            iNbEntiers --;
        }

    if (_iNbEntiers)
       *_iNbEntiers = iNbEntiers;
    if (_iNbDecim)
       *_iNbDecim = iNbDecim;
    if (_iPosDec)
       *_iPosDec = iPosDec;

    return bSigned;
    }

//////////////////////////////////////
//
// IsClipboardValid
//
// Fonction: Verifie que le contenu du Clipboard est correct vis a vis du format
//          du nombre
//
// P.E.: AUCUN
//
// P.S.: tru si OK
//
//////////////////////////////////////
bool __fastcall CEditNum::IsClipboardValid()
    {
    AnsiString  aTemp           = Text;
    int         OldStart        = SelStart;

    try
        {
        // Suppression des car selectionnes pour remplacement
        if( SelLength != 0 )
            aTemp.Delete( OldStart + 1, SelLength );

        // Insertion du Clip dans Text temporaire
        aTemp.Insert(Clipboard()->AsText, OldStart + 1 );

        // Tests approfondis
        return( IsNumValid( Concatene( aTemp )));
        }

    catch(...)
       {
       ASSERT(false);
       }
    return false;
    }



//////////////////////////////////////
//
// IsNumValid( AnsiString aNum )
//
// Fonction: Verfie que le nombre est valide en tous points
//
// P.E.: Le Nombre
//
// P.S.: true si OK
//
//////////////////////////////////////
bool __fastcall CEditNum::IsNumValid( const AnsiString &aNum )
   {
   AnsiString  aTemp;
   int         i;
   bool        bCntEntiers     = true; // flag pour comptage des entiers / decimales
   int         iNbEntiers      = 0;
   signed int  iNbDecim        = -1;
   int         iNbPtsDecim     = 0; // nb de pts decimaux
   int         iMaskNbEntiers;
   bool        bSigned         = false;
    AnsiString  aValidCars      = AnsiString( "0123456789.,- " );


    try
        {
        if( aNum.IsEmpty())
            return true ;

        for (i=1 ; i <= aNum.Length() ; i++)
            {
            // Test si caracteres numeriques
            aTemp = aNum[i];
            if((signed)strcspn( aTemp.c_str(), aValidCars.c_str()) == aTemp.Length())
               {
               /// Gestion de la puissance 10 ('10e-15')
               /////////////////////////////////////////////
               if (aTemp.UpperCase() == 'E')
                  {
                  AnsiString aPuissance;
                  int iNbPuissance10;

                  aPuissance = EXTRAIRE_CH(aNum, i+1, aNum.Length());
                  try{
                     iNbPuissance10 = aPuissance.ToInt();
                     }
                  catch(EConvertError &e)
                     {
                     return false;
                     }
                  iNbEntiers += iNbPuissance10;
                  if (iNbEntiers < 0)
                     iNbEntiers = 0;
                  iNbDecim -= iNbPuissance10;
                  if (iNbDecim < 0)
                     iNbDecim = 0;
                  break;
                  }
               else
                  return false;
               }

            if( aNum[i] == DecimalSeparator )
                {
                bCntEntiers = false;
                iNbPtsDecim ++;
                if( iNbPtsDecim > 1 )
                    return( false );
                }
            else if( aNum[i] == '-' )
                {
                if( bSigned )
                    return( false );
                bSigned = true;
                break;
                }
            if( bCntEntiers )
                iNbEntiers ++;
            else
                iNbDecim ++;
            }

        // Calcul taille entier & decimal du Mask
        /////////////////////////////////////////
        DecompNum( Mask, &iMaskNbEntiers, NULL, NULL);

        if(iNbEntiers > iMaskNbEntiers)
            return( false );

        // Test d'appartenance aux valeurs Min et Max imposees
        if( aNum.ToDouble() < Min || aNum.ToDouble() > Max )
            return( false );

        if( bSigned && aNum.Length() == 2 && aNum[2] == '0' )
            Font->Color = FColorPositive;
        else if( bSigned )
            Font->Color = FColorNeg;
        else
            Font->Color = FColorPositive;

        }
    catch(...)
        {
        ShowMessage( "Erreur dans la fonction IsNumValid (Contrôle : "+Name+")");
        }

   return true;
   }



//////////////////////////////////////
//
// IsNumInMiddle( AnsiString aText, char Key )
//
// Fonction: Verifie que le nombre + la touche enfoncee appartient bien au masque
//              + maximum
//
// P.E.: Le nombre
//       Le chiffre enfonce
//
// P.S.: true si OK
//
//////////////////////////////////////
bool __fastcall CEditNum::IsNumInMiddle(const AnsiString &aText, char Key)
{
AnsiString  aFuturValeur        = aText;
AnsiString  aMax;
__int64  l1;
__int64  l2;
int         iNbEntiers;
int         iNbDecim;
int         iMaxNbEntiers;
int         PosDec;
int         PosDecMax;

try
   {
   aFuturValeur.Insert( Key, SelStart + 1 );
   aMax = Concatene(Format(Max));

   DecompNum(aFuturValeur, &iNbEntiers, &iNbDecim, &PosDec);
   if (!aFuturValeur.IsEmpty() && aFuturValeur[1] == '-')
      {
      if (Min == D_NS)
         aMax = GetMaskNumeric();
      else
         aMax = Concatene(Format(Min));
      }
   else
      aMax = Concatene(Format(Max));

   if (aMax[1] == '-')
      aMax.Delete(1, 1); //On passe la chaine en valeur "absolue"
   if (aFuturValeur[1] == '-')
      aFuturValeur.Delete(1, 1); //On passe la chaine en valeur "absolue"

   DecompNum(aMax, &iMaxNbEntiers, NULL, &PosDecMax);

   if(iNbEntiers > iMaxNbEntiers)
       return false;
   else if(iNbEntiers == iMaxNbEntiers)
       {
       l1 = StrToInt64(aFuturValeur.SubString(1, iNbEntiers));
       l2 = StrToInt64(aMax.SubString(1, iNbEntiers));
       if(l1 > l2)
           return false;
       else if(l1 == l2)
           {
           if(PosDec != 0)
              {
              l1 = StrToInt64(aFuturValeur.SubString(PosDec+1, iNbDecim));
              l2 = StrToInt64(aMax.SubString(PosDecMax+1, iNbDecim));
              if(l1 > l2)
                 return false;
              }
           }
       }
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(330), e);
   return false;
   }
return true;
}





//////////////////////////////////////
//
// CalcNbSpaces
//
// Fonction: Calcule le nombre d'espaces necessaires pour le formatage
//
// P.E.: AUCUN
//
// P.S.: Le nombre d'espaces necessaires
//
//////////////////////////////////////
int __fastcall CEditNum::CalcNbSpaces()
    {
    int i;
    int PosDec;
    int CntSpaces;

    DecompNum( Mask, NULL, NULL, &PosDec);

    i = PosDec - 1;

    if( i >= 0 )
        CntSpaces = ( i - 1 ) / 3;
    else
        CntSpaces = ( Mask.Length() - 1 ) / 3;

    return( CntSpaces );
    }


/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres de sortie :

Valeur retournée :
*******************************************************************************/
TColor __fastcall CEditNum::SetColorNeg(TColor CouleurNegative)
{
int iSveHeight;
try
   {
   FColorNeg = CouleurNegative;

   if(!inherited::Text.IsEmpty() && inherited::Text[1] == '-')
      {
      iSveHeight = Height;
      Font->Color = FColorNeg;
//Lorsque la hauteur du composant est trop faible, le fait de modifier la fonte
//agrandie le composant, on remet donc la hauteur initiale
      Height = iSveHeight;
      }
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(350), e);
   }
return CouleurNegative;
}

/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres de sortie :

Valeur retournée :
*******************************************************************************/
TColor __fastcall CEditNum::SetColorPositive(TColor CouleurPositive)
{
int iSveHeight;
try
   {
   FColorPositive = CouleurPositive;

   if(inherited::Text.IsEmpty() || inherited::Text[1] != '-')
      {
      iSveHeight = Height;
      Font->Color = FColorPositive;
//Lorsque la hauteur du composant est trop faible, le fait de modifier la fonte
//agrandie le composant, on remet donc la hauteur initiale
      Height = iSveHeight;
      }
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(360), e);
   }
return CouleurPositive;
}

/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres de sortie :

Valeur retournée :
*******************************************************************************/
void __fastcall CEditNum::PerdreLaDonnee(signed int Inutilise)
{
try
   {
#ifdef _DEBUG
//   ShowMessage("Composant : "+Name+"\nLa propriété MaxLength ne peut pas être modifiée "
//               +"directement, elle est modifiée par l'intermédiaire de la propriété \"Mask\"");
#endif
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(370), e);
   }
}

/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres de sortie :

Valeur retournée :
*******************************************************************************/
void __fastcall CEditNum::MyOnChange (TObject* Sender)
{
try
   {
   //SI le nombre est valide
   if (m_OnChange && (Text.IsEmpty()/* && NSActive*/
                  || !Text.IsEmpty() && Text.AnsiCompare("-") != 0 && Concatene(Text).ToDouble() >= Min))
      m_OnChange(Sender);
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(380), e);
   }
}

/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres de sortie :

Valeur retournée :
*******************************************************************************/
void __fastcall CEditNum::SetOnChange(TNotifyEvent OnChange)
{
m_OnChange  = OnChange;
OldOnChange = OnChange;
}

bool __fastcall CEditNum::EstCorrectementRempliDefault( void)
{
  return( !Text.IsEmpty() && (Valeur != 0) && (!StateNS) );
}

//------------------------------------------------------------------------------
void __fastcall CEditNum::MyOnEnter (TObject* Sender)
{
    AfficherBoutonCalculette (FbCalc);

    if (m_pOnEnter)
       m_pOnEnter(Sender);
}

//------------------------------------------------------------------------------
void __fastcall CEditNum::MyOnExit  (TObject* Sender)
{
    if (FbCalc) {
        // on cache le bouton si on ne peux pas cliquer dessus
        if (    (ScreenToClient(Mouse->CursorPos).x < Width
             ||  ScreenToClient(Mouse->CursorPos).x > Width + m_pbCalc->Width)
             || (ScreenToClient(Mouse->CursorPos).y < 0
             ||  ScreenToClient(Mouse->CursorPos).y > Height)
           ) {
            AfficherBoutonCalculette(false);
            }
    }
if (m_pOnExit)
   m_pOnExit(Sender);
}

//------------------------------------------------------------------------------
void __fastcall CEditNum::sbCalcClick( TObject *pSender)
{
    Calc->AfficherCalc(this, Text, OnSetValue);
}

//------------------------------------------------------------------------------
void __fastcall CEditNum::OnSetValue(const AnsiString &aValue)
{
    Text = aValue;
//    SetFocus();
}
//------------------------------------------------------------------------------
void __fastcall CEditNum::PositionnerBoutonCalculette()
{
 if (m_pbCalc)
   {
   m_pbCalc->Left   = Left + Width;
   m_pbCalc->Top    = Top;
   m_pbCalc->Height = Height;
   m_pbCalc->Width  = 20;
   }
}

//------------------------------------------------------------------------------
void __fastcall CEditNum::AfficherBoutonCalculette(bool bAfficher)
{
   if (bAfficher && m_pbCalc)
      return;

   if (bAfficher)
      {
       ASSERT(!m_pbCalc);
       // construction de bouton pour afficher la calculatrice
       m_pbCalc  = new TBitBtn  ((TComponent *)NULL);
       m_pbCalc ->OnClick   = sbCalcClick;
       m_pbCalc ->OnExit    = MyOnExit;
       m_pbCalc ->NumGlyphs = 1;
       m_pbCalc ->TabStop   = false;
       m_pbCalc ->Glyph->LoadFromResourceName(( int)HInstance, "CALC");
       m_pbCalc ->Parent    = Parent;
       PositionnerBoutonCalculette();
       // ajout de la calculatrice
       Calc = new TfCalculatrice(this);
       }
   else
      {
          if (Calc) {
            delete Calc;                 Calc     = NULL;
          }
          if (m_pbCalc) {
              delete m_pbCalc;             m_pbCalc = NULL;
          }
      }
}

/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres de sortie :

Valeur retournée :
*******************************************************************************/
AnsiString __fastcall CEditNum::GetMaskNumeric() const
{
AnsiString aTmp = FMask;

try
   {
   //Conversion du Mask en version numérique
   for (int i=1 ; i<=aTmp.Length() ; i++)
      {
      if(aTmp[i] != SEP_DEC && aTmp[i] != SEP_DEC_2)
         aTmp[i] = '9';
      if(aTmp[i] == SEP_DEC_2 || aTmp[i] == SEP_DEC)
         aTmp[i] = DecimalSeparator;
      }
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(470), e);
   }
return aTmp;
}

/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres de sortie :

Valeur retournée :
*******************************************************************************/
double __fastcall CEditNum::GetDefaultValNS() const
{
try
   {
   switch(FTypeVal)
        {
        case eShInt:
            return SH_NS;

        case eUShInt:
            return USH_NS;

        case eInt:
            return I_NS;

        case eUInt:
            return UI_NS;

        case eLong:
            return L_NS;

        case eFloat:
            return F_NS;

        case eDouble:
        case eCurrency:
            return D_NS;

        default :
            ASSERT(false);
        }
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(480), e);
   }
return D_NS;
}
/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres de sortie :

Valeur retournée :
*******************************************************************************/
AnsiString __fastcall CEditNum::DoubleToAnsi(double dNombre)
{
AnsiString aNombre;
int i;
try
   {
   aNombre = dNombre;
   if ((i = aNombre.LastDelimiter(DecimalSeparator)) != 0)
      aNombre[i] = SEP_DEC;
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(490), e);
   }
return aNombre;
}

/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres de sortie :

Valeur retournée :
*******************************************************************************/
double __fastcall CEditNum::AnsiToDouble(AnsiString aNombre)
{
int i;
AnsiString aD_NS = AnsiString(D_NS);

//Génère D_NS sous forme de chaîne
if ((i = aD_NS.LastDelimiter(",.")) != 0) //converti le séparateur de millier de la chaîne en séparateur de millier "local"
   aD_NS[i] = DecimalSeparator;

if ((i = aNombre.LastDelimiter(",.")) != 0) //converti le séparateur de millier de la chaîne en séparateur de millier "local"
   aNombre[i] = DecimalSeparator;

//Nous sommes obligé de comparer les chaînes textes car lorsque l'on converti
//une chaîne valant D_NS en double, cela explose sous certains Windows 98
if (aNombre == aD_NS)
   return D_NS;
else
   return aNombre.ToDouble();
}

/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres de sortie :

Valeur retournée :
*******************************************************************************/
bool __fastcall CEditNum::ConcatenerSiBesoin(AnsiString *aNombre, int iClientWidth)
{
SIZE TaillePix;
HDC HDCComposant = GetDC(Handle);
HFONT SaveFont;
bool bConcatene = false;

try
   {
   //SI le texte ne tient pas dans le composant (avec les séparateurs de milliers)
   //On le concatène.
   SaveFont = SelectObject(HDCComposant, Font->Handle);
   if(GetTextExtentPoint32(HDCComposant,
                           aNombre->c_str(), aNombre->Length(), &TaillePix))
      {
      if (TaillePix.cx >= iClientWidth-2 /*2 pixels de marge*/)
         {
         *aNombre = Concatene(*aNombre);
         bConcatene = true;
         }
      }
   else
      ASSERT(false);

   SelectObject(HDCComposant,SaveFont);
   ReleaseDC(Handle, HDCComposant);
   }
catch(Exception &e)
   {
   EICDisplayException(TAG(510), e);
   }
return bConcatene;
}

//------------------------------------------------------------------------------
namespace Ceditnum
    {
    void __fastcall PACKAGE Register()
        {
        TComponentClass classes[1] = {__classid(CEditNum)};
        RegisterComponents("EIC Ctrlstd", classes, 0);
        }
    }

